#tag Class
Protected Class NSNotificationObserver
Inherits CocoaDelegate
	#tag Event
		Function DelegateClassName() As String
		  
		  return "MLNSNotificationObserver"
		  
		End Function
	#tag EndEvent

	#tag Event
		Function DelegateMethods() As Tuple()
		  
		  dim methodList() as Tuple
		  methodList.Append kNotificationSelector : FPtr(AddressOf DispatchNotification) : "v@:@"
		  
		  return methodList
		  
		End Function
	#tag EndEvent


	#tag Method, Flags = &h1000
		Sub Constructor(handler as NSNotificationInterface = nil)
		  
		  // construct a delegate and accept an optional delegate handler which is a NSNotificationInterface instance
		  // this permits to use this class in two modes:
		  //
		  // 1. Without subclassing, just instantiating it passing a NSNotificationInterface member that will handle
		  //     the events (eg. a window or another class). The handler can also be changed at any time setting the DelegateHandler
		  //     property.
		  //
		  // 2. Subclassing this class and handling the events. This can be also done dragging an instance of this class in a window.
		  //
		  
		  // store the handler
		  DelegateHandler = handler
		  
		  // call super to construct the object
		  super.Constructor
		  
		  // initialize the dictionary for keeping track of notification centers
		  subscribedCenters = new Dictionary
		  
		  // raise the Open event (for use by subclasses or instances dragged to a window)
		  raiseEvent Open()
		  
		  
		  
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Destructor()
		  
		  // unregister from notification centers to avoid runtime errors
		  self.Unregister
		  
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h21
		Private Shared Sub DispatchNotification(id as Ptr, sel as Ptr, notification as Ptr)
		  
		  // dispatch the message to the right instance handler
		  
		  #pragma StackOverflowChecking false
		  
		  #pragma unused sel
		  
		  if CocoaDelegateMap.HasKey(id) then // lookup the delegate instance
		    dim w as WeakRef = CocoaDelegateMap.Lookup(id, new WeakRef(nil))
		    dim obj as NSNotificationObserver = NSNotificationObserver(w.Value) // get the delegate instance
		    
		    // be sure to have a valid object
		    if obj = nil then
		      return
		    end if
		    
		    // call the notification handler if the notification is not nil
		    if notification <> nil then
		      
		      obj.NotificationHandler new NSNotification(notification)
		      
		    end if
		    
		  end if
		  
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h21
		Private Sub NotificationHandler(notification as NSNotification)
		  
		  // handle the message and call the handler or fire the event
		  
		  if DelegateHandler <> nil then
		    DelegateHandler.NotificationReceived(notification)
		  else
		    raiseEvent NotificationReceived(notification)
		  end if
		  
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Register(notificationName as String, notificationSender as Ptr = nil, notificationCenter as NSNotificationCenter = nil)
		  
		  // try to resolve the notification name as a Cocoa string constant
		  dim s as String = Cocoa.StringConstant(notificationName)
		  if s <> "" then
		    notificationName = s
		  end if
		  
		  // set the notification center in case the user wants a particular center instead of default
		  if notificationCenter = nil then
		    notificationCenter = NSNotificationCenter.DefaultCenter
		  end if
		  
		  // register self as observer
		  notificationCenter.AddObserver self, kNotificationSelector, notificationName, new NSObject(notificationSender)
		  
		  // keep track of notification centers to automatically unregister when self is deallocated
		  if not subscribedCenters.hasKey(notificationCenter.id) then
		    subscribedCenters.value(notificationCenter.id) = notificationCenter
		  end if
		  
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Unregister(notificationCenter as NSNotificationCenter = nil)
		  
		  // unregister as observer from the given notificationCenter or from all notification centers if notificationCenter is nil
		  
		  if notificationCenter = nil then
		    for each center as NSNotificationCenter in subscribedCenters.Values()
		      center.RemoveObserver self
		    next
		  else
		    dim center as NSNotificationCenter = subscribedCenters.Value(notificationCenter.id)
		    if center <> nil then
		      center.RemoveObserver self
		    end if
		  end if
		  
		End Sub
	#tag EndMethod


	#tag Hook, Flags = &h0
		Event NotificationReceived(notification as NSNotification)
	#tag EndHook

	#tag Hook, Flags = &h0
		Event Open()
	#tag EndHook


	#tag Property, Flags = &h0
		DelegateHandler As NSNotificationInterface
	#tag EndProperty

	#tag Property, Flags = &h21
		Private subscribedCenters As Dictionary
	#tag EndProperty


	#tag Constant, Name = kNotificationSelector, Type = String, Dynamic = False, Default = \"dispatchNotification:", Scope = Private
	#tag EndConstant


	#tag ViewBehavior
		#tag ViewProperty
			Name="ClassName"
			Group="Behavior"
			Type="String"
			EditorType="MultiLineEditor"
			InheritedFrom="CocoaDelegate"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Description"
			Group="Behavior"
			Type="String"
			EditorType="MultiLineEditor"
			InheritedFrom="NSObject"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Index"
			Visible=true
			Group="ID"
			InitialValue="-2147483648"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Left"
			Visible=true
			Group="Position"
			InitialValue="0"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Name"
			Visible=true
			Group="ID"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Super"
			Visible=true
			Group="ID"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Top"
			Visible=true
			Group="Position"
			InitialValue="0"
			InheritedFrom="Object"
		#tag EndViewProperty
	#tag EndViewBehavior
End Class
#tag EndClass
